﻿package com.cf.core.model.diagram.config {
	import com.cf.core.model.diagram.config.LabelData;
	import com.cf.core.Utils.tools;
	import com.cf.core.Utils.debug;
	public class range{
		private var G_min:int;
		public function get min():int { return G_min }
		public function set min(_n:int):void { G_min = _n }
		private var G_max:int;
		public function get max():int { return G_max }
		public function set max(_n:int):void { G_max = _n }
		private var G_offset:Boolean;
		public function get offset():Boolean { return G_offset }
		public function set offset(_n:Boolean):void { G_offset = _n }
		private var G_def_cellSize:Number;
		public function set defSize(_n:Number){G_def_cellSize=_n}
		public function get defSize():Number{return G_def_cellSize}
		private var G_type:LabelData;
		public function set type(_s:LabelData):void{G_type=_s}
		public function get type():LabelData{return G_type}
		
		
		private var G_different:Number;	// 最大&最細差額;
		public function get different():Number{return Math.abs(this.max - this.min)}
		private var G_view_distance:Number;
		public function set distance(_n:Number):void { G_view_distance = _n; run(); }
		public function get distance():Number { return G_view_distance }
		private var G_step:Number;		// 繪圖時每一格遞增的基準數 for Data.
		//public function set step(_n:Number):void {if (0<_n && _n<=this.max) G_step = _n;}
		public function get step():Number { return G_step }
		private var G_view_cellSize:Number;
		//public function set cellSize(_n:Number):void { G_view_cellSize = _n; run(); }
		public function get cellSize():Number { return G_view_cellSize }
		private var G_view_row:int;
		public function get row():int{return G_view_row}
		
		
		public function range( _min:Number, _max:Number, _cellSize:Number, _distance:Number) {
			// debug.msg("Range : min("+_min+") max("+_max+") cellSize("+_cellSize+") distance("+_distance+")");
			G_step = 0;			// preinit
			G_offset = false;	// preinit
			if (_min == _max) {
				// Range : _min & _max can't be same. loading init value
				RELEASE();
			}else{
				G_min = _min;
				G_max = _max;
				G_view_distance = _distance;
				this.defSize = _cellSize;
				run();			// we have distance now. find the rest.
				if ( _cellSize >= this.distance ) {
					debug.msg("Range : distance is too small, retouch to default min cell size["+this.defSize+"]");
				}else{
					// G_view_cellSize = _cellSize;
				}//if
			}//if
		}//fn
		public function toString():String {
			var _str:String = 'Range : '+ this.min +' ~ ' + this.max + ', height=' + this.distance;
				_str += "\t\r - table draw in size="+ this.cellSize +"px row="+this.row+" step="+this.step;
			return _str;
		}//fn
		public function RELEASE(e:*= null):void {
			debug.msg("Range : init/release");
			G_min = G_max = 0;
			G_view_cellSize = G_view_distance = 0;
		}//fn
		
		private function run():void {
			// we have distance now. find the rest.
			var _scid:Object = suggestCellInDistance();
			G_step = _scid.step;			// this.step
			G_view_cellSize = _scid.size;	// this.cellSize
			G_view_row = int(_scid.row);			// this.row
		}//fn
		protected function suggestCellInDistance():Object {
			var _C2:Number = 2, _C5:Number = 5, _C10:Number = 10,
				_next:Number, _size:Number = -1, _step:Number = -1, _row:Number=-1,
				_tmpC:Object, _flag:Boolean = false;
			// we try to found it out how many parts the differenet can be split to.
			if ( this.different >= 1) {
				_next = 10;		// do it in 20%, 50%, 100%
			}else{
				_next = 0.1;	// do it in 0.2%, 0.5%, 0.01%
			}//if
			while ( !_flag ) {
				// step=2,5,10,20,50,100......1000000, size=[number]
				_tmpC = closest( _C2, _C5, _C10);
				if ( _step == -1 || Math.abs(_tmpC.size-this.defSize) < Math.abs(_size-this.defSize) ) {
					_step = _tmpC.step;
					_size = _tmpC.size;		// new value smaller
					_row = _tmpC.row;
				}//if
				// debug.msg("Current Selected step="+ _step +" size="+_size+"px row="+_row+" - - Range : ["+ _C2 +", "+ _C5 +", "+ _C10 +"]min step="+_tmpC.step+" size="+ _tmpC.size +" check:"+ cellNoInStep(_tmpC.step)+"<1");
				_C2 = _C2*_next;
				_C5 = _C5*_next;
				_C10 = _C10*_next;
				if ( cellNoInStep(_tmpC.step) <= 1 ) _flag = true;	// (data range)/scale = can't be small then 1:1, we should find the ans aready.
			}//while
			return Object({step:_step, size:_size, row:_row});
		}//fn
		
		// 以差額計算 scale 差距
		/** ref :
		 * Math.int 無條件去尾數
		 * Math.floor 無條件退位
		 * Math.round 四捨五入
		 * Math.ceil 無條件進位
		 */
		protected function closest( _C2:Number, _C5:Number, _C10:Number):Object {
			var _arrSize = [Math.floor(this.distance / cellNoInStep(_C2)), Math.floor(this.distance / cellNoInStep(_C5)), Math.floor(this.distance / cellNoInStep(_C10))];
			var _arrDiff = [Math.abs(_arrSize[0] - this.defSize), Math.abs(_arrSize[1] - this.defSize), Math.abs(_arrSize[2] - this.defSize)];
			var _min:Number = tools.min(_arrDiff);
			var _flag:int;
			var _step:Number;
			if (_min == _arrDiff[0]) { 			_step = _C2; _flag = 0;}
			else if (_min == _arrDiff[1]) {	 	_step = _C5; _flag = 1;}
			else { 								_step = _C10; _flag = 2;}
			var _row:int = int( this.distance / _arrSize[_flag]);
			// debug.msg("Default Size=" + this.defSize +" step="+_step+" minSize="+_arrSize[_flag]+" row="+_row);
			return Object({ step:_step, size:_arrSize[_flag], row:_row });
		}//fn
		protected function cellNoInStep(_step:Number):Number {
			return Math.ceil(this.different / _step);
		}//fn
		protected function noOfCell(_pixal:Number):int {
			return int(this.distance / _pixal);
		}//fn
		protected function sizeOfCell(_no:int):Number {
			return Math.round(this.distance / _no);
		}//fn
	}//class
}//package